package com.java.shop.ware.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.java.common.constant.MqConstant;
import com.java.common.to.OrderTo;
import com.java.common.to.SkuHasStockTo;
import com.java.common.to.WareSkuLockTo;
import com.java.common.to.mq.StockLockedTo;
import com.java.common.utils.PageUtils;
import com.java.common.utils.Query;
import com.java.common.utils.R;
import com.java.shop.ware.dao.WareSkuDao;
import com.java.shop.ware.entity.WareOrderTaskDetailEntity;
import com.java.shop.ware.entity.WareOrderTaskEntity;
import com.java.shop.ware.entity.WareSkuEntity;
import com.java.shop.ware.exception.NoStockException;
import com.java.shop.ware.feign.OrderFeignService;
import com.java.shop.ware.feign.ProductFeignService;
import com.java.shop.ware.service.WareOrderTaskDetailService;
import com.java.shop.ware.service.WareOrderTaskService;
import com.java.shop.ware.service.WareSkuService;
import com.java.shop.ware.vo.OrderVo;
import com.java.shop.ware.vo.ProductToWareVo;
import com.java.shop.ware.vo.SkuWareHasStockVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {
    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    WareOrderTaskService wareOrderTaskService;

    @Autowired
    OrderFeignService orderFeignService;

    @Autowired
    WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    RabbitTemplate rabbitTemplate;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageCondition(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wr = new QueryWrapper<>();

        String wareId = (String) params.get("wareId");
        if(!StringUtils.isEmpty(wareId)){
            wr.eq("ware_id",wareId);
        }

        String skuId = (String) params.get("skuId");
        if(!StringUtils.isEmpty(skuId)){
            wr.eq("sku_id",skuId);
        }

        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),wr
        );

        return new PageUtils(page);
    }


    @Transactional
    @Override
    public void addStock(ProductToWareVo wareVo) {
        QueryWrapper<WareSkuEntity> wr = new QueryWrapper<>();
        wr.eq("sku_id",wareVo.getSkuId());
        wr.eq("ware_id",wareVo.getWareId());
        List<WareSkuEntity> list = this.list(wr);
        if(list.size() == 0){
            WareSkuEntity entity = new WareSkuEntity();
            entity.setStockLocked(0);
            //TODO 远程查询sku_name的值并设置，自己消化异常不抛出则不回滚，后续分布式事务优化
            try {
                R sku = productFeignService.info(wareVo.getSkuId());
                if(sku.getCode() == 0){
                    Map<String,Object> skuInfo = (Map<String, Object>) sku.get("skuInfo");
                    entity.setSkuName((String) skuInfo.get("skuName"));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            BeanUtils.copyProperties(wareVo,entity);
            this.save(entity);
        }else{
            baseMapper.addStock(wareVo);
        }
    }


    /**
     * 获取sku对应的库存状态（true,false）
     * @param skuIds
     * @return
     */
    @Override
    public List<SkuHasStockTo> hasStock(List<Long> skuIds) {
        if(skuIds.size() <= 0) return null;
        return skuIds.stream().map(skuId->{
            SkuHasStockTo to = new SkuHasStockTo();
            Integer stockNum = baseMapper.getStockBySkuId(skuId);
            to.setSkuId(skuId);
            if(stockNum > 0) to.setHasStock(true);
            else to.setHasStock(false);
            return to;
        }).collect(Collectors.toList());
    }

    /**
     * 锁库存
     * @param to
     * @return
     */
    @Transactional
    @Override
    public Boolean orderLockStock(WareSkuLockTo to) throws NoStockException{
        /**
         * 保存库存工作单详情
         */
        WareOrderTaskEntity taskEntity = new WareOrderTaskEntity();
        taskEntity.setOrderSn(to.getOrderSn());
        wareOrderTaskService.save(taskEntity);

        //1.按照收货地址，找到最近一个有货的仓库，锁定库存（不做）
        //2.找到每个商品在哪些仓库有库存
        List<WareSkuLockTo.OrderItemTo> locks = to.getLocks();
        List<SkuWareHasStockVo> wareList = locks.stream().map(item -> {
            SkuWareHasStockVo vo = new SkuWareHasStockVo();
            //查询商品在那个仓库有库存
            List<Long> wareIds = baseMapper.getWareBySKuId(item.getSkuId(),item.getNum());
            vo.setSkuId(item.getSkuId());
            vo.setWareIds(wareIds);
            vo.setNum(item.getNum());
            return vo;
        }).collect(Collectors.toList());


        /* 锁定库存 */
        for(SkuWareHasStockVo vo : wareList){
            Long skuId = vo.getSkuId();
            List<Long> wareIds = vo.getWareIds();
            //没有任何仓库可以容纳这个库存
            if(wareIds == null || wareIds.size() == 0){
                log.error("商品id:{},库存不足",skuId);
                throw new NoStockException(skuId);
            }
            Boolean flag = false;

            //循环尝试在仓库中锁库存
            for(Long wareId : wareIds){
                Long count = baseMapper.lockSkuStock(skuId, wareId, vo.getNum());
                if(count == 1L){
                    //库存锁定成功
                    flag = true;
                    WareOrderTaskDetailEntity detailEntity = new WareOrderTaskDetailEntity(null, skuId, null, vo.getNum(), taskEntity.getId(), wareId, 1);
                    wareOrderTaskDetailService.save(detailEntity);
                    StockLockedTo stockLockedTo = new StockLockedTo();
                    BeanUtils.copyProperties(detailEntity,stockLockedTo);
                    rabbitTemplate.convertAndSend(MqConstant.ware_exchangeName,MqConstant.ware_toDeadRoutingKey,stockLockedTo);
                    break;
                }else{
                    //当前库存锁定失败，尝试下一个库存
                }
            }

            //当前商品没有锁定成功
            if(!flag) {
                log.error("商品id:{},锁定库存失败",skuId);
                throw new NoStockException(skuId);
            }
        }
        return true;
    }

    /**
     * 自动解锁库存
     */
    @Override
    public void unLockStock(StockLockedTo to) {
        Long taskId = to.getTaskId();
        Long id = to.getId();
        WareOrderTaskDetailEntity detailEntity = wareOrderTaskDetailService.getById(id);
        if(detailEntity != null && detailEntity.getLockStatus() == 1) {
            //有数据，只能证明库存锁定成功，接下来还要判断order的事务是否回滚
            WareOrderTaskEntity taskEntity = wareOrderTaskService.getById(taskId);
            R r = orderFeignService.getInfoByOrderSn(taskEntity.getOrderSn());
            if (r.getCode() == 0) {
                //订单数据返回成功
                OrderVo orderVo = JSON.parseObject(r.getData(), OrderVo.class);
                if (orderVo == null || orderVo.getStatus() == 4) {
                    //订单已取消,或者订单自己已经回滚，数据库查不到，解锁库存
                    baseMapper.unLockStock(to);
                    WareOrderTaskDetailEntity update = new WareOrderTaskDetailEntity();
                    update.setId(detailEntity.getId());
                    update.setLockStatus(2);
                    wareOrderTaskDetailService.updateById(update);
                }
            }else{
                log.error("WareSkuServiceImpl::unLockStock(StockLockedTo to)远程调用order数据失败！");
                throw new RuntimeException("远程调用失败");
            }
        }
    }

    /**
     * 防止订单服务卡顿，导致订单状态一直改变不了，库存消息优先到期，查订单状态肯定是新建的，什么都不做就消费掉消息
     * 导致卡顿的订单锁定的库存永远得不到释放
     * @param to
     */
    @Override
    public void unLockStock(OrderTo to) {
        String orderSn = to.getOrderSn();
        WareOrderTaskEntity taskEntity = wareOrderTaskService.getOne(new QueryWrapper<WareOrderTaskEntity>()
                .eq("order_sn", orderSn));
        if(taskEntity != null){
            List<WareOrderTaskDetailEntity> list = wareOrderTaskDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>()
                    .eq("task_id", taskEntity.getId())
                    .eq("lock_status", 1));

            if(list.size() != 0){
                for (WareOrderTaskDetailEntity detailEntity : list) {
                    if(detailEntity.getLockStatus() == 1){
                        StockLockedTo stockLockedTo = new StockLockedTo();
                        BeanUtils.copyProperties(detailEntity,stockLockedTo);
                        baseMapper.unLockStock(stockLockedTo);
                        WareOrderTaskDetailEntity update = new WareOrderTaskDetailEntity();
                        update.setId(detailEntity.getId());
                        update.setLockStatus(2);
                        wareOrderTaskDetailService.updateById(update);
                    }
                }
            }
        }
    }
}